package com.ruoyi.business.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.ruoyi.bizsys.domain.*;
import com.ruoyi.bizsys.mapper.*;
import com.ruoyi.bizsys.service.*;
import com.ruoyi.bizsys.utils.BizConstants;
import com.ruoyi.business.Vo.CustReduceRes;
import com.ruoyi.business.component.RepaymentMqSendService;
import com.ruoyi.business.mapper.BRepaymentMapper;
import com.ruoyi.business.processIou.service.ProcessForIouDefferredService;
import com.ruoyi.business.service.*;
import com.ruoyi.common.constant.LoanConstants;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.enums.RspEnmu;
import com.ruoyi.common.exception.BusinessException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.FeishuUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.uuid.IdUtils;
import com.ruoyi.common.utils.uuid.SnowflakeIdWorker;
import com.ruoyi.extdata.common.config.PayStackConfig;
import com.ruoyi.extdata.service.IExternalApiService;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.client.producer.SendStatus;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @Author: Jamnsin
 * @Date: 2021/6/15 11:51 下午
 */
@Slf4j
@Service
public class RepaymentServiceImpl extends BaseService implements IRepaymentService {

    @Autowired
    ILoanOffsetService loanOffsetService;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    @Lazy
    IBLoanInfoService loanInfoService;

    @Autowired
    BRepaymentMapper bRepaymentMapper;

    @Autowired
    ICreditAccountService creditAccountService;

    @Autowired
    DoCalCustReduce doCalCustReduce;

    @Autowired
    ILoanIouService loanIouService;

    @Autowired
    PayStackConfig payStackConfig;

    @Autowired
    IExternalApiService externalApiService;

    @Autowired
    ILoanService loanService;

    @Autowired
    IRepaymentOrderService repaymentOrderService;

    @Autowired
    LoanDeferredOrderMapper loanDeferredOrderMapper;

    @Autowired
    @Lazy
    IBLoanInfoService bLoanInfoService;

    @Autowired
    ReduceConfigMapper reduceConfigMapper;

    @Autowired
    RepaymentOrderMapper repaymentOrderMapper;

    @Autowired
    ICustReduceOrderService custReduceOrderService;

    @Autowired
    @Lazy
    IRepaymentSmsService iRepaymentSmsService;

    @Autowired
    RedissonClient redissonClient;

    @Autowired
    RepaymentMqSendService repaymentMqService;

    @Autowired
    BRepaymentMapper repaymentMapper;

    private static final String EMAIL = "@LCserver.com";

    @Autowired
    ProcessForIouDefferredService processForIouDefferredService;
    @Resource
    LoanIouMapper loanIouMapper;

    @Autowired
    ProductDeferredInfoMapper productDeferredInfoMapper;

    @Autowired
    LoanIouDeferredMapper loanIouDeferredMapper;

    @Autowired
    @Lazy
    IDoRepaymentLastService doRepaymentLastService;

    @Override
    public void repayment(RepaymentOrder repaymentOrder) {
        //锁住客户账户再操作
        String lockKey = RedisCache.CUST_ACCOUNT_LOCK_KEY_PREFIX + repaymentOrder.getCustNo();
        RLock lock = redisCache.lock(lockKey);
        long start = System.currentTimeMillis();
        try {
            CreditAccount creditAccount = creditAccountService.getNormalAcountOnLoan(repaymentOrder.getCustNo());
            if (null == creditAccount) {
                lock.unlock();
                return;
            }
            repaymentNoLock(repaymentOrder);
        } catch (Exception e) {
            log.error("Repayment 线程 sleep 异常", e);
        } finally {
            //释放锁
            long end = System.currentTimeMillis();
            log.info("锁占用时间，耗时：" + (end - start) + " ms");
            lock.unlock();
        }
    }

    @Override
    public void repaymentNoLock(RepaymentOrder repaymentOrder) {

        //执行冲账
        LoanOffset loanOffset = saveLoanOffset(repaymentOrder);
        //冲账
        loanInfoService.doLoanRepaymentGetInfo(loanOffset);
    }

    @Override
    public void repaymentNoLockForDefer(RepaymentOrder repaymentOrder) {
        //生成子借据，生成offset、
        LoanOffset loanOffset = saveIouDeferLoanOffset(repaymentOrder);
        //冲账
        loanInfoService.doLoanRepaymentGetInfoForDefer(loanOffset);
    }

    /**
     * 生成子借据
     *
     * @param repaymentOrder
     * @return
     */
    private LoanOffset saveIouDeferLoanOffset(RepaymentOrder repaymentOrder) {
        LoanDeferredOrder loanDeferredOrder = loanDeferredOrderMapper.selectByOrderNo(repaymentOrder.getLoanDeferOrderNo());
        //获取借据
        LoanIou loanIou = loanIouService.getLoanIouByLoanSerialNo(repaymentOrder.getLoanSerialNo());

        LoanIouDeferred loanIouDeferred = new LoanIouDeferred();
        loanIouDeferred.setCustNo(repaymentOrder.getCustNo());
        loanIouDeferred.setLoanSerialDeferredNo(IdWorker.getId());
        loanIouDeferred.setLoanSerialNo(repaymentOrder.getLoanSerialNo());
        loanIouDeferred.setProductDeferredId(loanDeferredOrder.getProductDeferredId());
        loanIouDeferred.setLoanDeferOrderNo(repaymentOrder.getLoanDeferOrderNo());
        loanIouDeferred.setInterestRate(loanDeferredOrder.getInterestRate());
        loanIouDeferred.setServiceRate(loanDeferredOrder.getServiceRate());
        String nowRepayDate = loanIou.getRepayDate();
        if (null != loanIou.getIsDeferred() && loanIou.getIsDeferred() == 1) {
            nowRepayDate = loanIou.getDeferredRepayDate();
        }

        // 计算新的到期日
        loanIouDeferred.setRepayDate(DateUtils.getNewDay(nowRepayDate, loanDeferredOrder.getNumDeferredDay()));
        loanIouDeferred.setPeriodNum(loanDeferredOrder.getNumDeferredDay());
        BigDecimal serviceFee = loanIou.getLoanPrincipal().subtract(loanIou.getRepaidPrincipal()).multiply(loanDeferredOrder.getServiceRate());
        loanIouDeferred.setServiceFee(serviceFee);
        loanIouDeferred.setRepaidServiceFee(BigDecimal.ZERO);
        BigDecimal interestFee = loanIou.getLoanPrincipal().subtract(loanIou.getRepaidPrincipal()).multiply(loanDeferredOrder.getInterestRate().multiply(new BigDecimal(loanDeferredOrder.getNumDeferredDay())));
        loanIouDeferred.setInterestFee(interestFee);
        loanIouDeferred.setRepaidInterestFee(BigDecimal.ZERO);

        loanIouDeferred.setContractNo(IdUtils.generateContractNo());
        loanIouDeferred.setStatus(0);
        loanIouDeferred.setState(BizConstants.BIZ_STATUS_1);
        loanIouDeferredMapper.insert(loanIouDeferred);

        LoanOffset loanOffset = new LoanOffset();
        loanOffset.setLoanSerialDeferredNo(loanIouDeferred.getLoanSerialDeferredNo());
        loanOffset.setCustNo(repaymentOrder.getCustNo());
        loanOffset.setLoanSerialNo(repaymentOrder.getLoanSerialNo());
        loanOffset.setRepaymentNo(repaymentOrder.getRepaymentNo());
        loanOffset.setActionType(repaymentOrder.getActionType());
        loanOffset.setAmt(repaymentOrder.getRepaymentAmt());

        loanOffset.setPayTime(repaymentOrder.getPayTime());

        loanOffset.setLoanPrincipal(repaymentOrder.getLoanPrincipal());
        loanOffset.setRepaidPrincipal(repaymentOrder.getRepaidPrincipal());
        loanOffset.setServiceFee(repaymentOrder.getServiceFee());
        loanOffset.setRepaidServiceFee(repaymentOrder.getRepaidServiceFee());
        loanOffset.setLoanInterest(repaymentOrder.getLoanInterest());
        loanOffset.setRepaidInterest(repaymentOrder.getRepaidInterest());
        if (repaymentOrder.getLateFee() == null) {
            repaymentOrder.setLateFee(BigDecimal.ZERO);
        }
        if (repaymentOrder.getReduceFee() == null) {
            repaymentOrder.setReduceFee(BigDecimal.ZERO);
        }
        loanOffset.setLateFee(repaymentOrder.getLateFee());// 不需要 wqg沟通过 后期遇到延迟冲账的场景去回溯
        loanOffset.setRepaidLateFee(repaymentOrder.getRepaidLateFee());

        loanOffset.setLoanOffsetStatus(BizConstants.LOAN_OFFSET_STATUS_WAIT);
        loanOffset.setState(UserConstants.BUSINESS_NORMAL);
        //设置子借据
        loanOffset.setLoanSerialDeferredNo(loanIouDeferred.getLoanSerialDeferredNo());
        loanOffsetService.insertLoanOffset(loanOffset);
        return loanOffset;
    }

    /**
     * Qucik-repay 减免金额冲账，先服务费再本金
     *
     * @param repaymentOrder
     */
    @Override
    public void doReduceAmtStrike(RepaymentOrder repaymentOrder) {
        BigDecimal repaymentAmt = repaymentOrder.getRepaymentAmt();
        String actionType = repaymentOrder.getActionType();
        repaymentOrder.setActionType(BizConstants.LOAN_REPAYMENT_ORDER_TYPE_QR_REDUCE);
        repaymentOrder.setRepaymentAmt(repaymentOrder.getReduceFee());
        // 生成优惠金额的offset 冲账
        LoanOffset loanOffset = saveLoanOffsetReduce(repaymentOrder);
        // 本金冲账 还原信息
        repaymentOrder.setRepaymentAmt(repaymentAmt);
        repaymentOrder.setActionType(actionType);
        // 开始冲账，只进行计算，更新iou和本身的4个数据、reduce_fee
        doCalReduceAmt(loanOffset, repaymentOrder);
    }

    /**
     * 催收还款
     *
     * @param loan
     * @param account
     * @param custBankCard
     * @param repayAmt
     * @return
     */
    @Override
    public RepaymentOrder doCollectionRepaymentAction(LoanIou loan, CreditAccount account, CustBankCard custBankCard, BigDecimal repayAmt) {
        RepaymentOrder repaymentOrder = null;
        //锁住客户账户再操作
        String lockKey = LoanConstants.CUST_ACCOUNT_LOCK_KEY_PREFIX + account.getCustNo();
        RLock lock = redisCache.lock(lockKey);
        try {
            long start = System.currentTimeMillis();
            //发起代扣申请记录
            repaymentOrder = bLoanInfoService.createRepaymentOrder(loan, custBankCard.getAuthorizationCode(),
                    BizConstants.LOAN_REPAYMENT_ORDER_TYPE_COLLECTION, repayAmt, null);
            doCollectionTrans(account, custBankCard, repaymentOrder);
            //无需重试
            long end = System.currentTimeMillis();
            log.info("催收点击还款锁占用时间，耗时：" + (end - start) + " ms");
        } catch (Exception e) {
            log.error("催收还款", e);
            String className = this.getClass().getName();
            String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
            FeishuUtils.sendFeishuToMonit(className + "." + methodName, "催收还款", loan.getCustNo(), loan.getLoanSerialNo(), e);
        } finally {
            lock.unlock();
        }
        return repaymentOrder;
    }


    /**
     * 执行催收的代扣-成功后发送短信，进行冲账更新账户信息，删除锁
     *
     * @param account
     * @param custBankCard
     * @param repaymentOrder
     */
    private void doCollectionTrans(CreditAccount account, CustBankCard custBankCard, RepaymentOrder repaymentOrder) {
        if (null != repaymentOrder) {
            //发起代扣
            repaymentOrder.setPayTransSerialNo(IdUtils.reqId());
            Map<String, Boolean> res = bLoanInfoService.payTransWithholdTrans(repaymentOrder, custBankCard.getEmail());
            if (!res.get("isFail")) {
                if (res.get("resStatus")) {
                    repaymentMqService.collectionRepaymentMq(repaymentOrder, account);
                }
//
//                sendSmsForOPerate(repaymentOrder);
//                repaymentService.repaymentNoLock(repaymentOrder);
//                //更新账户信息
//                bLoanInfoService.updateAccount(account);
            } else {
                log.info("催收点击还款：{},代扣失败", repaymentOrder.getCustNo());
            }
        } else {
            log.info("催收点击还款：{},订单创建失败", repaymentOrder.getCustNo());
        }
    }

    /**
     * QucikRepay 生成还款订单-执行代扣操作
     *
     * @param serialNo
     * @param bankCard
     * @param reduceFlag
     * @return
     */
    @Override
    public boolean createRepaymentOrderAndPayTrans(String serialNo, CustBankCard bankCard, String reduceFlag) {
        log.info("主动还款-生成还款订单-执行代扣操作：serialNo = {},bankCard = {}，reduceFlag = {}", serialNo, bankCard.toString(), reduceFlag);
        String custNo = bankCard.getCustNo();
        boolean result = false;
        //锁住客户账户再操作
        String lockKey = LoanConstants.CUST_ACCOUNT_LOCK_KEY_PREFIX + custNo;
        RLock lock = redisCache.lock(lockKey);
        try {
            long start = System.currentTimeMillis();
            result = lockedAndPross(serialNo, bankCard, reduceFlag, custNo);
            long end = System.currentTimeMillis();
            log.info("锁占用时间，耗时：" + (end - start) + " ms");
        } catch (Exception e) {
            log.error("QucikRepay主动还款", e);
            String className = this.getClass().getName();
            String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
            FeishuUtils.sendFeishuToMonit(className + "." + methodName, "QucikRepay主动还款", custNo, serialNo, e);
        } finally {
            lock.unlock();
        }
        return result;
    }

    /**
     * 锁住之后处理业务
     *
     * @param serialNo
     * @param bankCard
     * @param reduceFlag
     * @param custNo
     */
    private boolean lockedAndPross(String serialNo, CustBankCard bankCard, String reduceFlag, String custNo) {
        LoanIou loanIou = getLoanIou(serialNo, custNo);
        if (null != loanIou) {
            // 含有减免信息 在loanIou设置减免信息
            flagTrueAndsetReduceAmt(reduceFlag, loanIou);
            // 创建订单
            RepaymentOrder repaymentOrder = bLoanInfoService.createRepaymentOrder(
                    loanIou,
                    bankCard.getAuthorizationCode(),
                    BizConstants.LOAN_REPAYMENT_ORDER_TYPE_OPERATE,
                    null,
                    "Active");
            return goPayTransWithholdTrans(bankCard, reduceFlag, loanIou, repaymentOrder);
        }
        return false;
    }

    /**
     * 订单创建成功发起代扣
     *
     * @param bankCard
     * @param reduceFlag
     * @param loanIou
     * @param repaymentOrder
     * @return
     */
    private boolean goPayTransWithholdTrans(CustBankCard bankCard, String reduceFlag, LoanIou loanIou,RepaymentOrder repaymentOrder) {
        boolean result = false;
        if (null != repaymentOrder) {
            // 订单成功，继续判断是否含有减免信息，更新repaymentOrder CustReduceOrderId和减免金额字段
            repaymentOrder = createReduceOrderAndbackrepayOrder(reduceFlag, loanIou, repaymentOrder);
            //发起代扣
            repaymentOrder.setPayTransSerialNo(IdUtils.reqId());
            Map<String, Boolean> res = bLoanInfoService.payTransWithholdTrans(repaymentOrder, bankCard.getEmail());
            if (!res.get("isFail") && res.get("resStatus")) {
                // ps 注意，发送扣款成功，也会再次发送webhook消息到服务器
                result = true;
                // 推送MQ
                repaymentMqService.selfRepaymentMq(repaymentOrder);
            } else {
                log.info("主动还款：{},代扣失败", repaymentOrder.getCustNo());
            }
        } else {
            log.info("主动还款：{},订单创建失败", repaymentOrder.getCustNo());
        }
        return result;
    }

    @Override
    @Transactional
    public void selfRepaymentForMqListener(RepaymentOrder repaymentOrder) {
        repaymentOrder.setRepayStatus(BizConstants.REPAYMENT_ORDER_STATUS_SUCCESS);
        repaymentOrderMapper.updateById(repaymentOrder);
        LoanIou loanIou = loanIouService.getLoanIouByLoanSerialNo(repaymentOrder.getLoanSerialNo());
        if (LoanIou.LOAN_IOU_STATUS_SETTLE == loanIou.getIouStatus()) {
            log.info(repaymentOrder.getRepaymentNo() + "iou结清了，进入溢缴款");
            // 进入溢缴款
            bLoanInfoService.doOverFlowAndWallet(repaymentOrder.getRepaymentAmt(), repaymentOrder);
            return;
        }
        //冲账
        calcuRepay(repaymentOrder);
        doRepaymentLastService.lastInitRuleInAndAutoMat(repaymentOrder);
        setCardCanUse(repaymentOrder);
        sendSmsForOPerate(repaymentOrder);
    }

    /**
     * 延期的 不带钱包的余额的
     *
     * @param repaymentOrder
     * @param creditAccount
     */
    @Override
    @Transactional
    public void selfDeFerRepaymentForMqListener(RepaymentOrder repaymentOrder, CreditAccount creditAccount) {
        //冲账
        //如果实际交易发生时间逾期产生了罚息，延期产品未生效，走产品冲销流程；
        //如果实际交易发生时间未产生逾期费用，则延期产品生效，需要减免已产生的罚息，减免逻辑：
        //实际交易发生时间<=借据到期时间+罚息宽限期，则减免已生成的所有罚息；
        //减免罚息后，进入延期产品冲销流程。
        // 判断iou 剩余本金大于等于延期产品还款最低本金
        repaymentOrder.setRepayStatus(BizConstants.REPAYMENT_ORDER_STATUS_SUCCESS);
        repaymentOrderMapper.updateById(repaymentOrder);
        LoanDeferredOrder loanDeferredOrder = loanDeferredOrderMapper.selectByOrderNo(repaymentOrder.getLoanDeferOrderNo());
        LoanIou loanIou = loanIouService.getLoanIouByLoanSerialNo(repaymentOrder.getLoanSerialNo());
        if (LoanIou.LOAN_IOU_STATUS_SETTLE == loanIou.getIouStatus()) {
            log.info(repaymentOrder.getRepaymentNo() + "iou结清了，进入溢缴款");
            // 进入溢缴款
            bLoanInfoService.doOverFlowAndWallet(repaymentOrder.getRepaymentAmt(), repaymentOrder);

            loanDeferredOrder.setStatus(LoanDeferredOrder.STATUS_FAILED);
            loanDeferredOrderMapper.updateById(loanDeferredOrder);
            return;
        }
        // 原来的时间 和现在的时间defer时间比较
        String oldRepayDate = loanIou.getRepayDate();
        if (null != loanIou.getProductId() && loanIou.getProductId() == 1) {
            oldRepayDate = loanIou.getDeferredRepayDate();
        }

        boolean canBuy = checkCanBuyDefer(repaymentOrder);
        if (canBuy) {
            calcuRepayForDefer(repaymentOrder);

            LoanIou loanIouForPdf = loanIouService.getOne(new QueryWrapper<LoanIou>().eq("loan_serial_no", loanDeferredOrder.getLoanSerialNo()));
            LoanIouDeferred loanIouDeferred = loanIouDeferredMapper.selectOne(new QueryWrapper<LoanIouDeferred>().select("service_fee", "period_num", "interest_fee", "contract_no", "repay_date", "service_fee", "create_time").eq("loan_serial_deferred_no", loanIouForPdf.getLoanSerialDeferredNo()));
            loanService.createDeferredContractPdf(loanDeferredOrder.getRepayAmt(), loanIouForPdf, loanIouDeferred);
        } else {
            // 不能购买延期
            loanDeferredOrder.setStatus(LoanDeferredOrder.STATUS_FAILED);
            loanDeferredOrderMapper.updateById(loanDeferredOrder);
            repaymentOrder.setActionType(BizConstants.LOAN_REPAYMENT_ORDER_TYPE_OPERAT_WALLET_PAYSTACK_FAILD);
            //执行冲账
            LoanOffset loanOffset = saveLoanOffset(repaymentOrder);
            //冲账
            loanInfoService.doLoanRepaymentGetInfo(loanOffset);
        }
        iRepaymentSmsService.smsSendDeferd(repaymentOrder, oldRepayDate);


    }

    /**
     * 延期还款+钱包部分还款
     * @param repaymentOrder
     * @param creditAccount
     */
    @Override
    @Transactional
    public void selfDeFerNotAllRepaymentForMqListener(RepaymentOrder repaymentOrder, CreditAccount creditAccount) {
        // 判断iou 剩余本金大于等于延期产品还款最低本金
        repaymentOrder.setRepayStatus(BizConstants.REPAYMENT_ORDER_STATUS_SUCCESS);
        repaymentOrderMapper.updateById(repaymentOrder);

        LoanDeferredOrder loanDeferredOrder = loanDeferredOrderMapper.selectByOrderNo(repaymentOrder.getLoanDeferOrderNo());
        LoanIou loanIou = loanIouService.getLoanIouByLoanSerialNo(repaymentOrder.getLoanSerialNo());
        if (LoanIou.LOAN_IOU_STATUS_SETTLE == loanIou.getIouStatus()) {
            log.info(repaymentOrder.getRepaymentNo() + "iou结清了，标记钱包成功，进入溢缴款");
            loanDeferredOrder.setStatus(LoanDeferredOrder.STATUS_FAILED);
            loanDeferredOrderMapper.updateById(loanDeferredOrder);

            // 标记钱包成功
            RepaymentOrder repaymentOrderWallet = repaymentOrderMapper.getDetailByPayTransSerialNo(loanDeferredOrder.getWalletNo());
            repaymentOrderWallet.setRepayStatus(BizConstants.REPAYMENT_ORDER_STATUS_SUCCESS);
            repaymentOrderMapper.updateById(repaymentOrderWallet);

            doRepaymentLastService.updateWalletOrderToSuccess(repaymentOrderWallet, true);
            // 进入溢缴款
            bLoanInfoService.doOverFlowAndWallet(repaymentOrderWallet.getRepaymentAmt(), repaymentOrderWallet);

            // 卡的钱进入溢缴款
            bLoanInfoService.doOverFlowAndWallet(repaymentOrder.getRepaymentAmt(), repaymentOrder);

            return;
        }
        // 原来的时间 和现在的时间defer时间比较
        String oldRepayDate = loanIou.getRepayDate();
        if (null != loanIou.getProductId() && loanIou.getProductId() == 1) {
            oldRepayDate = loanIou.getDeferredRepayDate();
        }
        boolean canBuy = checkCanBuyDefer(repaymentOrder);

        if (canBuy) {
            //冲账
            calcuRepayForDeferWalletNotAll(repaymentOrder);

            LoanIou loanIouForPdf = loanIouService.getOne(new QueryWrapper<LoanIou>().eq("loan_serial_no", loanDeferredOrder.getLoanSerialNo()));
            LoanIouDeferred loanIouDeferred = loanIouDeferredMapper.selectOne(new QueryWrapper<LoanIouDeferred>().select("service_fee", "period_num", "interest_fee", "contract_no", "repay_date", "service_fee", "create_time").eq("loan_serial_deferred_no", loanIouForPdf.getLoanSerialDeferredNo()));
            loanService.createDeferredContractPdf(loanDeferredOrder.getRepayAmt(), loanIouForPdf, loanIouDeferred);

        } else {
            log.info("不能购买延期包：serial:{}", repaymentOrder.getLoanSerialNo());
            // 不能购买延期
            loanDeferredOrder.setStatus(LoanDeferredOrder.STATUS_FAILED);
            loanDeferredOrderMapper.updateById(loanDeferredOrder);

            // 生成paystack的loanOffset
            repaymentOrder.setActionType(BizConstants.LOAN_REPAYMENT_ORDER_TYPE_OPERAT_WALLET_PAYSTACK_FAILD);
            repaymentOrderMapper.updateById(repaymentOrder);
            LoanOffset loanOffset = saveLoanOffset(repaymentOrder);

            RepaymentOrder repaymentOrderWallet = repaymentOrderService.getDetailByPayTransSerialNo(loanDeferredOrder.getWalletNo());
            repaymentOrderWallet.setRepayStatus(BizConstants.REPAYMENT_ORDER_STATUS_SUCCESS);
            // 钱包还款购买延期失败动作
            repaymentOrderWallet.setActionType(BizConstants.LOAN_REPAYMENT_ORDER_TYPE_OPERAT_WALLET_FAILD);
            repaymentOrderService.updateRepaymentOrder(repaymentOrderWallet);

            LoanOffset loanOffsetWallet = saveOffsetWallet(loanOffset, repaymentOrderWallet);
            //冲账钱包还款
            loanInfoService.doLoanRepaymentGetInfo(loanOffsetWallet);
            // 更新钱包解冻
            doRepaymentLastService.updateWalletOrderToSuccess(repaymentOrderWallet, true);

            loanIou = loanIouService.getLoanIouByLoanSerialNo(repaymentOrder.getLoanSerialNo());
            if (LoanIou.LOAN_IOU_STATUS_SETTLE == loanIou.getIouStatus()) {
                log.info(repaymentOrder.getRepaymentNo() + "iou结清了，进入溢缴款");
                // 进入溢缴款
                bLoanInfoService.doOverFlowAndWallet(repaymentOrder.getRepaymentAmt(), repaymentOrder);
                return;
            }
            //冲paystack
            loanInfoService.doLoanRepaymentGetInfo(loanOffset);

        }
        iRepaymentSmsService.smsSendDeferd(repaymentOrder, oldRepayDate);

    }

    /**
     * 《非》延期还款+钱包部分还款
     *
     * @param repaymentOrder
     * @param creditAccountId
     */
    @Override
    @Transactional
    public void selfNotAllRepaymentForMqListener(RepaymentOrder repaymentOrder, long creditAccountId) {
        repaymentOrder = repaymentOrderMapper.getDetail(repaymentOrder.getRepaymentNo());
        if (null != repaymentOrder && repaymentOrder.getRepayStatus() == BizConstants.REPAYMENT_ORDER_STATUS_SUCCESS) {
            log.info("repaymentOrder.getRepayStatus():" + repaymentOrder.getRepayStatus());
            return;
        }
        repaymentOrder.setRepayStatus(BizConstants.REPAYMENT_ORDER_STATUS_SUCCESS);
        repaymentOrderMapper.updateById(repaymentOrder);
        LoanIou loanIou = loanIouService.getLoanIouByLoanSerialNo(repaymentOrder.getLoanSerialNo());
        if (LoanIou.LOAN_IOU_STATUS_SETTLE == loanIou.getIouStatus()) {
            log.info(repaymentOrder.getRepaymentNo() + "钱包还款,iou结清了，标记钱包成功，进入溢缴款");
            if (BizConstants.LOAN_REPAYMENT_ORDER_TYPE_OPERAT_WALLET.equals(repaymentOrder.getActionType())) {
                // 标记钱包成功
                doRepaymentLastService.updateWalletOrderToSuccess(repaymentOrder, false);
            }
            // 进入溢缴款
            bLoanInfoService.doOverFlowAndWallet(repaymentOrder.getRepaymentAmt(), repaymentOrder);
            return;
        }
        calcuRepayForWalletNotAll(repaymentOrder);
        //更新账户信息
        //bLoanInfoService.updateAccount(creditAccount);
        // 更新钱包解冻
        if (BizConstants.LOAN_REPAYMENT_ORDER_TYPE_OPERAT_WALLET.equals(repaymentOrder.getActionType())) {
            doRepaymentLastService.updateWalletOrderToSuccess(repaymentOrder, false);
            return;
        }
        doRepaymentLastService.lastInitRuleInAndAutoMat(repaymentOrder);
    }

    private void calcuRepayForWalletNotAll(RepaymentOrder repaymentOrder) {
        log.info("主动非延期还款：开始冲账：{}", repaymentOrder.toString());
        if (BizConstants.REPAYMENT_ORDER_STATUS_SUCCESS == repaymentOrder.getRepayStatus()) {
            repaymentNoLockForWalletNoAll(repaymentOrder);
            setCardCanUse(repaymentOrder);
        }
    }

    private void repaymentNoLockForWalletNoAll(RepaymentOrder repaymentOrder) {
        //生成offset
        LoanOffset loanOffset = saveLoanOffset(repaymentOrder);

        // 获取Wallet的PayTransSerialNo  BizConstants.PAY_TRANS_FLAG_PAY_ALL_WALLET
        // Wallet 的流水+常量拼接成wallet的paytrans 用于查询wallet的repayMentOrder
        String payTransSerialNo = repaymentOrder.getPayTransSerialNo().replaceAll(BizConstants.PAY_TRANS_FLAG_PAY_ALL_WALLET, "");
        RepaymentOrder repaymentOrderWallet = repaymentOrderService.getDetailByPayTransSerialNoStatusSucc(payTransSerialNo);

        LoanOffset loanOffsetWallet = saveOffsetWalletForRepayAll(loanOffset, repaymentOrderWallet);
        if (BizConstants.LOAN_REPAYMENT_ORDER_TYPE_OPERAT_WALLET.equals(repaymentOrder.getActionType())) {
            //冲账钱包还款
            loanInfoService.doLoanRepaymentGetInfoForWalletNotAll(loanOffsetWallet);
            return;
        }
        //冲账卡扣钱的还款---金额需要扣除上面的
        loanInfoService.doLoanRepaymentGetInfoForWalletNotAllByPayStsk(loanOffset);

    }


    private boolean checkCanBuyDefer(RepaymentOrder repaymentOrder) {
        // 查询iou 本金是否支持延期还款购买
        LoanIou loanIou = loanIouService.getLoanIouByLoanSerialNo(repaymentOrder.getLoanSerialNo());
        BigDecimal needPrincipal = loanIou.getLoanPrincipal().subtract(loanIou.getRepaidPrincipal());

        LoanDeferredOrder loanDeferredOrder = loanDeferredOrderMapper.selectByOrderNo(repaymentOrder.getLoanDeferOrderNo());
        BigDecimal minRepayPrincipal = loanDeferredOrder.getMinRepayPrincipal();
        if (needPrincipal.compareTo(minRepayPrincipal) >= 0) {
            log.info("延期还款查询后，needPrincipal>minRepayPrincipal:LoanDeferOrderNo{}", loanDeferredOrder.getLoanDeferOrderNo());
            return true;
//            // 查询 金额是否购买延期费用，可能产生了滞纳金，银行和三方支付导致的时间问题
//            BigDecimal neenPayIou = needPrincipal.add(loanIou.getLoanInterest()).add(loanIou.getServiceFee()).add(loanIou.getLateFee())
//                    .subtract(loanIou.getRepaidInterest()).subtract(loanIou.getRepaidServiceFee()).subtract(loanIou.getRepaidLateFee());
//            // getDateLateFee 在信息延迟到账到账需要减免
//            // 计算需要减免的费用
//            BigDecimal msgDeferedAmt = checkOffsetPayTime(loanIou,repaymentOrder);
//            BigDecimal neenPay = neenPayIou.subtract(msgDeferedAmt);
//            log.info("neenPayIou:{},msgDeferedAmt:{},neenPay:,{}",neenPayIou,msgDeferedAmt,neenPay);
//            if(neenPay.compareTo(repaymentOrder.getRepaymentAmt())<1){
//                return true;
//            }
        }

        return false;
    }

    private BigDecimal checkOffsetPayTime(LoanIou loanIou, RepaymentOrder repaymentOrder) {
        //还需要还的
        BigDecimal nowPrincipal = loanIou.getLoanPrincipal().subtract(loanIou.getRepaidPrincipal());
        BigDecimal lateFeeNeed = loanIou.getLateFee().subtract(loanIou.getRepaidLateFee()).subtract(loanIou.getFeeRemissionAmt());
        Date repayDate = DateUtils.parseDate(DateUtils.getNewDay(loanIou.getRepayDate(), loanIou.getLateFeeGracePeriod()));
        if (null != loanIou.getIsDeferred() && loanIou.getIsDeferred() == 1) {
            log.info("存在有效的延期包 判断系统减免时间：{}宽限日{}", loanIou.getDeferredRepayDate(), loanIou.getLateFeeGracePeriod());
            repayDate = DateUtils.parseDate(loanIou.getDeferredRepayDate());
        }
        log.info("判断系统减免时间：{}宽限日{}", repayDate, loanIou.getLateFeeGracePeriod());
        if (DateUtils.daysBetween(repayDate, new Date()) > 0) {
            //已经逾期，计算payTime和还款日的天数
            Date payTime = repaymentOrder.getPayTime();
            int LateFeeGracePeriod = loanIou.getLateFeeGracePeriod() == null ? 0 : loanIou.getLateFeeGracePeriod();
            int leftDays = DateUtils.daysBetween(payTime, new Date());
            if (leftDays > LateFeeGracePeriod) {
                leftDays = leftDays - LateFeeGracePeriod;
            }
            if (leftDays > 0) {
                //不是今天的，需要减免 延迟还款导致购买延期包的问题
                BigDecimal feeRemissionAmt = nowPrincipal.multiply(loanIou.getDateLateFee()).multiply(BigDecimal.valueOf(leftDays));
//                loanIou.setFeeRemissionAmt(feeRemissionAmt);
//                loanIouMapper.updateLateFee(loanIou);
                log.info("payTime:{},today:{},需要系统减免{}天,{}"
                        , DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_SLASH, payTime)
                        , DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_SLASH, new Date())
                        , leftDays, feeRemissionAmt);
                return lateFeeNeed.subtract(feeRemissionAmt);
            }
        }

        return lateFeeNeed;
    }


    /**
     * 卡完成扣款，删除redis锁
     *
     * @param repaymentOrder
     */
    private void setCardCanUse(RepaymentOrder repaymentOrder) {
        String redisKey = BizConstants.LOAN_REPAY_CARD + repaymentOrder.getLoanSerialNo();
        redisCache.deleteObject(redisKey);
    }

    /**
     * 开始冲账
     *
     * @param repaymentOrder
     */
    private void calcuRepay(RepaymentOrder repaymentOrder) {
        log.info("主动还款：开始冲账：{}", repaymentOrder.toString());
        // 判断是否有减免，有先进行减免冲账
        if (null != repaymentOrder.getCustReduceOrderId()) {
            doReduceAmtStrike(repaymentOrder);
        }
        repaymentNoLock(repaymentOrder);
    }

    /**
     * 开始冲账-延期还款无钱包
     *
     * @param repaymentOrder
     */
    private void calcuRepayForDefer(RepaymentOrder repaymentOrder) {
        log.info("主动延期还款：开始冲账：{}", repaymentOrder.toString());
        repaymentNoLockForDefer(repaymentOrder);
        setCardCanUse(repaymentOrder);
    }

    /**
     * 开始冲账-延期还款有钱包部分还款
     *
     * @param repaymentOrder
     */
    private void calcuRepayForDeferWalletNotAll(RepaymentOrder repaymentOrder) {
        log.info("主动延期还款：开始冲账：{}", repaymentOrder.toString());
        //生成offset
        LoanOffset loanOffset = saveIouDeferLoanOffset(repaymentOrder);

        LoanDeferredOrder loanDeferredOrder = loanDeferredOrderMapper.selectByOrderNo(repaymentOrder.getLoanDeferOrderNo());

        RepaymentOrder repaymentOrderWallet = repaymentOrderService.getDetailByPayTransSerialNo(loanDeferredOrder.getWalletNo());
        repaymentOrderWallet.setRepayStatus(BizConstants.REPAYMENT_ORDER_STATUS_SUCCESS);
        repaymentOrderService.updateRepaymentOrder(repaymentOrderWallet);

        LoanOffset loanOffsetWallet = saveOffsetWallet(loanOffset, repaymentOrderWallet);
        //冲账钱包还款
        loanInfoService.doLoanRepaymentGetInfoForDeferWalletNotAll(loanOffsetWallet);
        //冲账卡扣钱的还款---金额需要扣除上面的
        loanInfoService.doLoanRepaymentGetInfoForDeferWalletNotAllByPayStsk(loanOffset, loanOffsetWallet);
        setCardCanUse(repaymentOrder);
        // 更新钱包解冻
        doRepaymentLastService.updateWalletOrderToSuccess(repaymentOrderWallet, true);
    }

    private LoanOffset saveOffsetWalletForRepayAll(LoanOffset loanOffsetPayStask, RepaymentOrder repaymentOrder) {
        LoanOffset loanOffset = new LoanOffset();
        loanOffset.setCustNo(repaymentOrder.getCustNo());
        loanOffset.setLoanSerialNo(repaymentOrder.getLoanSerialNo());
        loanOffset.setRepaymentNo(repaymentOrder.getRepaymentNo());
        loanOffset.setActionType(repaymentOrder.getActionType());
        loanOffset.setAmt(repaymentOrder.getRepaymentAmt());

        loanOffset.setPayTime(loanOffsetPayStask.getPayTime());//paytime保持一致

        loanOffset.setLoanPrincipal(repaymentOrder.getLoanPrincipal());
        loanOffset.setRepaidPrincipal(repaymentOrder.getRepaidPrincipal());
        loanOffset.setServiceFee(repaymentOrder.getServiceFee());
        loanOffset.setRepaidServiceFee(repaymentOrder.getRepaidServiceFee());
        loanOffset.setLoanInterest(repaymentOrder.getLoanInterest());
        loanOffset.setRepaidInterest(repaymentOrder.getRepaidInterest());
        if (repaymentOrder.getLateFee() == null) {
            repaymentOrder.setLateFee(BigDecimal.ZERO);
        }
        if (repaymentOrder.getReduceFee() == null) {
            repaymentOrder.setReduceFee(BigDecimal.ZERO);
        }
        loanOffset.setLateFee(repaymentOrder.getLateFee());// 不需要 wqg沟通过 后期遇到延迟冲账的场景去回溯
        loanOffset.setRepaidLateFee(repaymentOrder.getRepaidLateFee());

        loanOffset.setLoanOffsetStatus(BizConstants.LOAN_OFFSET_STATUS_WAIT);
        loanOffset.setState(UserConstants.BUSINESS_NORMAL);
        loanOffsetService.insertLoanOffset(loanOffset);
        return loanOffset;
    }

    private LoanOffset saveOffsetWallet(LoanOffset loanOffsetPayStask, RepaymentOrder repaymentOrder) {
        LoanOffset loanOffset = new LoanOffset();
        loanOffset.setLoanSerialDeferredNo(loanOffsetPayStask.getLoanSerialDeferredNo());
        loanOffset.setCustNo(repaymentOrder.getCustNo());
        loanOffset.setLoanSerialNo(repaymentOrder.getLoanSerialNo());
        loanOffset.setRepaymentNo(repaymentOrder.getRepaymentNo());
        loanOffset.setActionType(repaymentOrder.getActionType());
        loanOffset.setAmt(repaymentOrder.getRepaymentAmt());

        loanOffset.setPayTime(loanOffsetPayStask.getPayTime());//paytime保持一致

        loanOffset.setLoanPrincipal(repaymentOrder.getLoanPrincipal());
        loanOffset.setRepaidPrincipal(repaymentOrder.getRepaidPrincipal());
        loanOffset.setServiceFee(repaymentOrder.getServiceFee());
        loanOffset.setRepaidServiceFee(repaymentOrder.getRepaidServiceFee());
        loanOffset.setLoanInterest(repaymentOrder.getLoanInterest());
        loanOffset.setRepaidInterest(repaymentOrder.getRepaidInterest());
        if (repaymentOrder.getLateFee() == null) {
            repaymentOrder.setLateFee(BigDecimal.ZERO);
        }
        if (repaymentOrder.getReduceFee() == null) {
            repaymentOrder.setReduceFee(BigDecimal.ZERO);
        }
        loanOffset.setLateFee(repaymentOrder.getLateFee());// 不需要 wqg沟通过 后期遇到延迟冲账的场景去回溯
        loanOffset.setRepaidLateFee(repaymentOrder.getRepaidLateFee());

        loanOffset.setLoanOffsetStatus(BizConstants.LOAN_OFFSET_STATUS_WAIT);
        loanOffset.setState(UserConstants.BUSINESS_NORMAL);
        loanOffsetService.insertLoanOffset(loanOffset);
        return loanOffset;
    }

    /**
     * 发送短信
     *
     * @param repaymentOrder
     */
    private void sendSmsForOPerate(RepaymentOrder repaymentOrder) {
        //如果repaymentOrder属于主动还款发短信
        LoanIou loanIou = loanIouService.getLoanIouByLoanSerialNo(repaymentOrder.getLoanSerialNo());
        if (BizConstants.LOAN_REPAYMENT_ORDER_TYPE_OPERATE.equals(repaymentOrder.getActionType())) {
            //发送通知短信
            if (repaymentOrder.getRepayStatus().equals(BizConstants.REPAYMENT_ORDER_STATUS_FAIL)) {
                iRepaymentSmsService.activeRepayment(repaymentOrder, loanIou, "fail");
            } else if (repaymentOrder.getRepayStatus().equals(BizConstants.REPAYMENT_ORDER_STATUS_SUCCESS)) {
                iRepaymentSmsService.activeRepayment(repaymentOrder, loanIou, "success");
            }
        }
    }

    /**
     * 生成减免订单返回 repaymentOrder repaymentOrder中设置订单id和减免金额 setCustReduceOrderId
     *
     * @param reduceFlag
     * @param loanIou
     * @param repaymentOrder
     * @return
     */
    private RepaymentOrder createReduceOrderAndbackrepayOrder(String reduceFlag, LoanIou loanIou, RepaymentOrder repaymentOrder) {
        if (("hasReduce").equals(reduceFlag)) {
            // 主动还款减免,创建订单，更新RepaymentOrder custorderid
            repaymentOrder = createReduceOrder(loanIou, repaymentOrder);
        }
        return repaymentOrder;
    }

    /**
     * 设置减免信息
     *
     * @param reduceFlag
     * @param loanIou
     */
    private void flagTrueAndsetReduceAmt(String reduceFlag, LoanIou loanIou) {
        if (("hasReduce").equals(reduceFlag)) {
            // 主动还款减免
            BigDecimal reduceAmt = getQucikRepayReduceAmt(loanIou);
            // 设置减免金额，用于createRepaymentOrder
            loanIou.setReduceAmt(reduceAmt);
        }
    }

    private LoanIou getLoanIou(String serialNo, String custNo) {
        //获取借据详情
        LoanIou LoanIouQuery = new LoanIou();
        LoanIouQuery.setCustNo(custNo);
        LoanIouQuery.setLoanSerialNo(serialNo);
        LoanIouQuery.setState(UserConstants.BUSINESS_NORMAL);
        LoanIou loanIou = loanIouService.getLoanIouDetail(LoanIouQuery);
        return loanIou;
    }

    /**
     * 主动还款含优惠信息
     *
     * @param repaymentOrder 1里面进行重写，repaymentorder创建好后
     *                       2创建减免订单，发起减免冲账，先付服务费再本金？要全部成功才能有状态 offset 状态是等待
     *                       3再发起卡金额扣款，成功-，发起冲账，更新2状态，更新全部状态
     *                       失败，webhook成功-发起冲账更新2状态，更新全部状态
     */
    private RepaymentOrder createReduceOrder(LoanIou loanIou, RepaymentOrder repaymentOrder) {
        ReduceConfig reduceConfig = reduceConfigMapper.getStatucOn();
        BigDecimal reduceAmt = doCalCustReduce.checkCustReduce(loanIou.getLoanSerialNo()).getReduceAmont();
        if (reduceAmt.compareTo(BigDecimal.ZERO) > 0) {
            CustReduceOrder custReduceOrder = getCustReduceOrder(loanIou, repaymentOrder, reduceConfig, reduceAmt);
            custReduceOrder.setId(SnowflakeIdWorker.getIdWorkerInstance().nextId());// 设置id
            repaymentOrder.setCustReduceOrderId(custReduceOrder.getId());
            custReduceOrderService.insertAndupdateRorder(custReduceOrder);
        }
        repaymentOrder.setReduceFee(reduceAmt);// 设置减免金额
        return repaymentOrder;
    }

    /**
     * 获取是否有减免权限
     *
     * @param loanIou
     * @return
     */
    private BigDecimal getQucikRepayReduceAmt(LoanIou loanIou) {
        BigDecimal reduceAmt = doCalCustReduce.checkCustReduce(loanIou.getLoanSerialNo()).getReduceAmont();
        return reduceAmt;
    }

    /**
     * CustReduceOrder set信息
     *
     * @param loanIou
     * @param repaymentOrder
     * @param reduceConfig
     * @param reduceAmt
     * @return
     */
    private CustReduceOrder getCustReduceOrder(LoanIou loanIou, RepaymentOrder repaymentOrder, ReduceConfig reduceConfig, BigDecimal reduceAmt) {
        CustReduceOrder custReduceOrder = new CustReduceOrder();
        custReduceOrder.setCustNo(loanIou.getCustNo());
        custReduceOrder.setRepaymentNo(repaymentOrder.getRepaymentNo());
        custReduceOrder.setActionType(ReduceConfig.ACTION_TYPE_QUICK_REPAY);

        custReduceOrder.setRepaymentAmtMin(reduceConfig.getRepaymentAmtMin());
        custReduceOrder.setNumLimit(reduceConfig.getNumLimit());
        custReduceOrder.setRate(reduceConfig.getRate());
        custReduceOrder.setDayLastAt(reduceConfig.getDayLastAt());
        custReduceOrder.setReduceAmtMin(reduceConfig.getReduceAmtMin());
        custReduceOrder.setReduceAmtMax(reduceConfig.getReduceAmtMax());

        custReduceOrder.setStatus(repaymentOrder.getRepayStatus());
        custReduceOrder.setServiceFee(loanIou.getServiceFee());
        custReduceOrder.setCurrentReduceAmt(reduceAmt);
        return custReduceOrder;
    }


    /**
     * 只进行计算，更新iou和本身的4个数据、reduce_fee
     *
     * @param loanOffset
     */
    private void doCalReduceAmt(LoanOffset loanOffset, RepaymentOrder repaymentOrder) {
        LoanIou loanIou = loanIouService.getLoanIouByLoanSerialNo(loanOffset.getLoanSerialNo());
        // 再次查询减免金额是否有效
        CustReduceRes custReduceRes = doCalCustReduce.checkCustReduce(loanOffset.getLoanSerialNo());
        if (custReduceRes.getReduceAmont().compareTo(BigDecimal.ZERO) > 0) {
            // 减免金额大于0 有效
            doCalReduceAmtNow(loanOffset, loanIou);
        } else {
            // repaymentOrder 去掉减免，和订单id 本次优惠次数不累加
            log.info("quick减免冲账,再次判断减免金额，未通过，不进行减免优惠{},{}", custReduceRes.toString(), repaymentOrder.getCustReduceOrderId());
            loanOffsetService.updateLoanOffsetAndRepayOrder(repaymentOrder, BizConstants.LOAN_REPAYMENT_ORDER_TYPE_QR_REDUCE);
        }
    }

    private void doCalReduceAmtNow(LoanOffset loanOffset, LoanIou loanIou) {
        // 减免金额冲账，先服务费再本金
        processServiceFee(loanOffset, loanIou);
        loanOffsetService.updateLoanOffset(loanOffset);
        loanIouService.updateLoanIou(loanIou);
    }

    /**
     * 支付了利息~进行服务费计算
     * 优惠券需要冲账不冲账的问题
     *
     * @param loanIou
     */
    private void processServiceFee(LoanOffset loanOffset, LoanIou loanIou) {
        BigDecimal amt = loanOffset.getAmt();
        // 支付了利息~进行服务费计算
        BigDecimal serviceFee = loanIou.getServiceFee().subtract(loanIou.getRepaidServiceFee());
        if (serviceFee.compareTo(BigDecimal.ZERO) != 0 && amt.compareTo(serviceFee) <= 0) {
            // 小于服务费
            serviceFee = serviceFee.subtract(amt).setScale(6, BigDecimal.ROUND_DOWN);
            // 剩余服务费
            loanIou.setRepaidServiceFee(loanIou.getRepaidServiceFee().add(amt));
            loanOffset.setOffsetServiceFee(amt);
            return;
        }
        if (serviceFee.compareTo(BigDecimal.ZERO) != 0 && amt.compareTo(serviceFee) == 1) {
            // 大于服务费
            // 扣除服务费
            amt = amt.subtract(serviceFee).setScale(6, BigDecimal.ROUND_DOWN);
            // 服务费还完了
            loanIou.setRepaidServiceFee(loanIou.getServiceFee());
            loanOffset.setOffsetServiceFee(serviceFee);
        }
        processLoanAmt(amt, loanOffset, loanIou);
    }

    /**
     * 开始还本金
     *
     * @param loanIou
     */
    private void processLoanAmt(BigDecimal amt, LoanOffset loanOffset, LoanIou loanIou) {
        BigDecimal amtLeft = loanIou.getLoanAmt().subtract(loanIou.getRepaidPrincipal());
        // 小于本金
        if (amtLeft.compareTo(BigDecimal.ZERO) != 0 && amt.compareTo(amtLeft) <= 0) {
            loanIou.setRepaidPrincipal(loanIou.getRepaidPrincipal().add(amt));
            loanOffset.setOffsetPrincipal(amt);
            return;
        }
        // 大于本金
        if (amtLeft.compareTo(BigDecimal.ZERO) != 0 && amt.compareTo(amtLeft) > 0) {
            loanIou.setRepaidPrincipal(loanIou.getLoanAmt());
            loanOffset.setOffsetPrincipal(amtLeft);
            log.info(loanIou.getLoanSerialNo() + ":存在多还款多{}", amt);
        } else {
            log.info(loanIou.getLoanSerialNo() + ":存在多还款多{}", amt);
        }
    }

    @Override
    public void repayment(LoanIou loanIou, String repaymentSn, String actionType, BigDecimal amt, BigDecimal reduceFee, int type) {
        //锁住客户账户再操作
        String lockKey = RedisCache.CUST_ACCOUNT_LOCK_KEY_PREFIX + loanIou.getCustNo();
        RLock lock = redisCache.lock(lockKey);
        long start = System.currentTimeMillis();
        try {
            repaymentNoLock(loanIou, repaymentSn, actionType, amt, reduceFee, type);
        } catch (Exception e) {
            log.error("Repayment 线程 sleep 异常", e);
        } finally {
            long end = System.currentTimeMillis();
            log.info("锁占用时间，耗时：" + (end - start) + " ms");
            lock.unlock();
        }
    }

    @Override
    public void repaymentNoLock(LoanIou loanIou, String repaymentSn, String actionType, BigDecimal amt, BigDecimal reduceFee, int type) {
        LoanOffset loanOffset = saveLoanOffset(loanIou, repaymentSn, actionType, amt, reduceFee, type);
        //冲账
        loanInfoService.doLoanRepaymentGetInfo(loanOffset);
    }

    @Override
    public RepaymentOrder getMaxSuccessDate(String loanSerialNo) {
        return bRepaymentMapper.getMaxSuccessDate(loanSerialNo);
    }

    /**
     * 还款试算-判断减免
     * 查询iou 获取最新的总剩余金额调用
     *
     * @param params
     * @return
     */
    @Override
    public JSONObject repaymentTrial(JSONObject params,LoanIou loanIou) {
        JSONObject res = new JSONObject();
        BigDecimal iouRepayAmt = LoanIou.calculationOverdueAmount(loanIou);
        log.info(params.getString("loanSerialNo") + "repaymentTrial::iou需要还" + iouRepayAmt);
        CustReduceRes checkCustReduce = doCalCustReduce.checkCustReduce(params.getString("loanSerialNo"));
        res.put("totalAmount", iouRepayAmt.subtract(checkCustReduce.getReduceAmont()));
        return res;
    }

    /**
     * 还款试算-延期包的-无减免判断
     * 查询iou 获取最新的总剩余金额调用
     *
     * @param params
     * @return
     */
    @Override
    public JSONObject repaymentTrialDeferred(JSONObject params) {
        JSONObject res = new JSONObject();
        LoanIou loanIou = loanIouMapper.getLoanIouByLoanSerialNo(params.getString("loanSerialNo"));
        res.put("totalAmount", processForIouDefferredService.getTotalAmountBy(params,loanIou));
        return res;
    }

    private LoanOffset saveLoanOffset(LoanIou loanIou, String repaymentSn, String actionType, BigDecimal amt, BigDecimal reduceFee, int type) {
        LoanOffset loanOffset = new LoanOffset();
        loanOffset.setCustNo(loanIou.getCustNo());
        loanOffset.setLoanSerialNo(loanIou.getLoanSerialNo());
        if (type == 1) {
            loanOffset.setRepaymentNo(repaymentSn);
        } else {
            loanOffset.setRemissionNo(repaymentSn);
        }

        loanOffset.setActionType(actionType);
        loanOffset.setAmt(amt);

        loanOffset.setLoanPrincipal(loanIou.getLoanPrincipal());
        loanOffset.setRepaidPrincipal(loanIou.getRepaidPrincipal());
        loanOffset.setServiceFee(loanIou.getServiceFee());
        loanOffset.setRepaidServiceFee(loanIou.getRepaidServiceFee());
        loanOffset.setLoanInterest(loanIou.getLoanInterest());
        loanOffset.setRepaidInterest(loanIou.getRepaidInterest());
        loanOffset.setLateFee(loanIou.getLateFee().subtract(reduceFee));
        loanOffset.setRepaidLateFee(loanIou.getRepaidLateFee());
        loanOffset.setReduceAmt(reduceFee);

        loanOffset.setLoanOffsetStatus(BizConstants.LOAN_OFFSET_STATUS_WAIT);
        loanOffset.setState(UserConstants.BUSINESS_NORMAL);
        loanOffsetService.insertLoanOffset(loanOffset);
        return loanOffset;
    }

    private LoanOffset saveLoanOffsetReduce(RepaymentOrder repaymentOrder) {
        LoanOffset loanOffset = new LoanOffset();
        loanOffset.setCustNo(repaymentOrder.getCustNo());
        loanOffset.setLoanSerialNo(repaymentOrder.getLoanSerialNo());
        loanOffset.setRepaymentNo(repaymentOrder.getRepaymentNo());
        loanOffset.setActionType(repaymentOrder.getActionType());
        loanOffset.setAmt(repaymentOrder.getRepaymentAmt());
        //获取最新借据
        LoanIou loanIou = loanIouService.getLoanIouByLoanSerialNo(repaymentOrder.getLoanSerialNo());
        if (null == loanIou) {
            String msg = "根据冲账借据号：" + repaymentOrder.getLoanSerialNo() + "未匹配到借据信息";
            log.error(msg);
            loanOffset.setLoanOffsetDesc(msg);
            loanOffset.setLoanOffsetStatus(BizConstants.LOAN_OFFSET_STATUS_FAIL);
        } else {
            //冲账前借据数据记录
            loanOffset.setLoanPrincipal(loanIou.getLoanPrincipal());
            loanOffset.setRepaidPrincipal(loanIou.getRepaidPrincipal());
            loanOffset.setLoanInterest(loanIou.getLoanInterest());
            loanOffset.setRepaidInterest(loanIou.getRepaidInterest());
            loanOffset.setServiceFee(loanIou.getServiceFee());
            loanOffset.setRepaidServiceFee(loanIou.getRepaidServiceFee());
            loanOffset.setLateFee(loanIou.getLateFee());
            loanOffset.setRepaidLateFee(loanIou.getRepaidLateFee());
            loanOffset.setReduceAmt(loanIou.getFeeRemissionAmt());
        }
        loanOffset.setLoanOffsetStatus(BizConstants.LOAN_OFFSET_STATUS_WAIT);
        loanOffset.setState(UserConstants.BUSINESS_NORMAL);
        loanOffsetService.insertLoanOffset(loanOffset);
        return loanOffset;
    }

    private LoanOffset saveLoanOffset(RepaymentOrder repaymentOrder) {
        LoanOffset loanOffset = new LoanOffset();
        loanOffset.setCustNo(repaymentOrder.getCustNo());
        loanOffset.setLoanSerialNo(repaymentOrder.getLoanSerialNo());
        loanOffset.setRepaymentNo(repaymentOrder.getRepaymentNo());
        loanOffset.setActionType(repaymentOrder.getActionType());
        loanOffset.setAmt(repaymentOrder.getRepaymentAmt());

        loanOffset.setPayTime(repaymentOrder.getPayTime());

        loanOffset.setLoanPrincipal(repaymentOrder.getLoanPrincipal());
        loanOffset.setRepaidPrincipal(repaymentOrder.getRepaidPrincipal());
        loanOffset.setServiceFee(repaymentOrder.getServiceFee());
        loanOffset.setRepaidServiceFee(repaymentOrder.getRepaidServiceFee());
        loanOffset.setLoanInterest(repaymentOrder.getLoanInterest());
        loanOffset.setRepaidInterest(repaymentOrder.getRepaidInterest());
        if (repaymentOrder.getLateFee() == null) {
            repaymentOrder.setLateFee(BigDecimal.ZERO);
        }
        if (repaymentOrder.getReduceFee() == null) {
            repaymentOrder.setReduceFee(BigDecimal.ZERO);
        }
        loanOffset.setLateFee(repaymentOrder.getLateFee());// 不需要 wqg沟通过 后期遇到延迟冲账的场景去回溯
        loanOffset.setRepaidLateFee(repaymentOrder.getRepaidLateFee());

        loanOffset.setLoanOffsetStatus(BizConstants.LOAN_OFFSET_STATUS_WAIT);
        loanOffset.setState(UserConstants.BUSINESS_NORMAL);
        loanOffsetService.insertLoanOffset(loanOffset);
        return loanOffset;
    }

    @Override
    public RepaymentOrder initRepaymentOrderFromLoanIou(LoanIou loanIou, String actionType, BigDecimal amount) {

        RepaymentOrder repaymentOrder = new RepaymentOrder();
        repaymentOrder.setRepaymentNo(IdUtils.reqId());
        repaymentOrder.setCustNo(loanIou.getCustNo());
        repaymentOrder.setLoanSerialNo(loanIou.getLoanSerialNo());
        repaymentOrder.setActionType(actionType);
        repaymentOrder.setLoanPrincipal(loanIou.getLoanPrincipal().subtract(loanIou.getRepaidPrincipal()));
        repaymentOrder.setServiceFee(loanIou.getServiceFee().subtract(loanIou.getRepaidServiceFee()));
        repaymentOrder.setLoanInterest(loanIou.getLoanInterest().subtract(loanIou.getRepaidInterest()));
        repaymentOrder.setLateFee(loanIou.getLateFee().subtract(loanIou.getRepaidLateFee()));
        repaymentOrder.setReduceFee(((loanIou.getFeeRemissionAmt() == null ? BigDecimal.ZERO : loanIou.getFeeRemissionAmt()).add(loanIou.getReduceAmt() == null ? BigDecimal.ZERO : loanIou.getReduceAmt())));
        repaymentOrder.setShouldRepaymentAmt(repaymentOrder.getLoanPrincipal().add(repaymentOrder.getServiceFee()).add(repaymentOrder.getLoanInterest().add(repaymentOrder.getLateFee())).subtract(repaymentOrder.getReduceFee()));
        repaymentOrder.setRepaymentAmt(amount);
        repaymentOrder.setRepayStatus(2);

        return repaymentOrder;
    }

    @Override
    public List<RepaymentOrder> getToActionTypeAndLoanSerialNo(String actionType, String loanSerialNo) {
        return repaymentMapper.getToActionTypeAndLoanSerialNo(actionType, loanSerialNo);
    }


    @Override
    public boolean createRepaymentOrderAndPayTransForDefer(String serialNo, CustBankCard bankCard, LoanDeferredOrder loanDeferredOrder) {
        log.info("主动还款延期包:生成还款订单-执行代扣操作:serialNo:{},bankCard:{}，loanDeferOrderNo：{}", serialNo, bankCard.toString(), loanDeferredOrder.getLoanDeferOrderNo());
        String custNo = bankCard.getCustNo();
        boolean result = false;
        //锁住客户账户再操作
        String lockKey = LoanConstants.CUST_ACCOUNT_LOCK_KEY_PREFIX + custNo;
        RLock lock = redisCache.lock(lockKey);
        try {
            long start = System.currentTimeMillis();
            result = lockedAndProssForDefer(serialNo, bankCard, custNo, loanDeferredOrder);
            long end = System.currentTimeMillis();
            log.info("锁占用时间延期包，耗时：" + (end - start) + " ms");
        } catch (Exception e) {
            log.error("QucikRepay主动还款延期包", e);
            String className = this.getClass().getName();
            String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
            FeishuUtils.sendFeishuToMonit(className + "." + methodName, "QucikRepay主动还款-延期包", custNo, serialNo, e);
        } finally {
            lock.unlock();
        }
        return result;
    }

    /**
     * 非延期,钱包全额还款的MQ处理方法
     */
    @Override
    @Transactional
    public void selfWalletRepaymentForMqListener(LoanIou loanIou, RepaymentOrder repaymentOrder) {
        repaymentOrder.setRepayStatus(BizConstants.REPAYMENT_ORDER_STATUS_SUCCESS);
        repaymentOrderMapper.updateById(repaymentOrder);
        loanIou = loanIouService.getLoanIouByLoanSerialNo(loanIou.getLoanSerialNo());
        if (LoanIou.LOAN_IOU_STATUS_SETTLE == loanIou.getIouStatus()) {
            log.info(repaymentOrder.getRepaymentNo() + "钱包全额还款,iou结清了，标记钱包成功，进入溢缴款");
            // 标记钱包成功
            doRepaymentLastService.updateWalletOrderToSuccess(repaymentOrder, false);
            // 进入溢缴款
            bLoanInfoService.doOverFlowAndWallet(repaymentOrder.getRepaymentAmt(), repaymentOrder);
            return;
        }
        // bLoanInfoService.doOverFlowAndWallet(repaymentOrder.getRepaymentAmt(),repaymentOrder);
        log.info("非延期，处理钱包全额还款的MQ，loanIou = {}，repaymentOrder = {}", loanIou, repaymentOrder);
        LoanOffset loanOffset = saveLoanOffsetWalletAll(repaymentOrder);

        // 冲账流程
        loanInfoService.doLoanRepaymentGetInfoForWalletAll(loanOffset);
        doRepaymentLastService.updateWalletOrderToSuccess(repaymentOrder, false);
        doRepaymentLastService.lastInitRuleInAndAutoMat(repaymentOrder);
    }

    /**
     * 延期钱包全额还款的MQ处理方法
     */
    @Override
    @Transactional
    public void selfDeFerWalletRepaymentForMqListener(LoanIou loanIou, RepaymentOrder repaymentOrder) {
        log.info("延期，处理钱包全额还款的MQ。。。。。{},{}", loanIou.toString(), repaymentOrder.toString());
        repaymentOrder.setRepayStatus(BizConstants.REPAYMENT_ORDER_STATUS_SUCCESS);
        repaymentOrderMapper.updateById(repaymentOrder);

        LoanDeferredOrder loanDeferredOrder = loanDeferredOrderMapper.selectByOrderNo(repaymentOrder.getLoanDeferOrderNo());

        loanIou = loanIouService.getLoanIouByLoanSerialNo(repaymentOrder.getLoanSerialNo());

        if (LoanIou.LOAN_IOU_STATUS_SETTLE == loanIou.getIouStatus()) {
            log.info(repaymentOrder.getRepaymentNo() + "iou结清了，标记钱包成功，进入溢缴款");
            // 标记钱包成功
            doRepaymentLastService.updateWalletOrderToSuccess(repaymentOrder, true);
            // 进入溢缴款
            bLoanInfoService.doOverFlowAndWallet(repaymentOrder.getRepaymentAmt(), repaymentOrder);

            loanDeferredOrder.setStatus(LoanDeferredOrder.STATUS_FAILED);
            loanDeferredOrderMapper.updateById(loanDeferredOrder);
            return;
        }
        // 判断iou 剩余本金大于等于延期产品还款最低本金
        boolean canBuy = checkCanBuyDefer(repaymentOrder);
        // 原来的时间 和现在的时间defer时间比较
        String oldRepayDate = loanIou.getRepayDate();
        if (null != loanIou.getProductId() && loanIou.getProductId() == 1) {
            oldRepayDate = loanIou.getDeferredRepayDate();
        }
        if (canBuy) {
            createLoanIouDeferred(loanDeferredOrder, loanIou, repaymentOrder);
            LoanOffset loanOffset = saveLoanOffsetDeferWallet(repaymentOrder, loanDeferredOrder);
            // 冲账流程
            loanInfoService.doLoanRepaymentGetInfoForDeferWalletAll(loanOffset);
            // CreditAccount creditAccount = creditAccountService.getNormalAcountOnLoan(loanIou.getCustNo());
            // 通知钱包冲账
            doRepaymentLastService.updateWalletOrderToSuccess(repaymentOrder, true);

            LoanIou loanIouForPdf = loanIouService.getOne(new QueryWrapper<LoanIou>().eq("loan_serial_no", loanDeferredOrder.getLoanSerialNo()));
            LoanIouDeferred loanIouDeferred = loanIouDeferredMapper.selectOne(new QueryWrapper<LoanIouDeferred>().select("service_fee", "period_num", "interest_fee", "contract_no", "repay_date", "service_fee", "create_time").eq("loan_serial_deferred_no", loanIouForPdf.getLoanSerialDeferredNo()));
            loanService.createDeferredContractPdf(loanDeferredOrder.getRepayAmt(), loanIouForPdf, loanIouDeferred);
        } else {
            // 不能够买延期
            loanDeferredOrder.setStatus(LoanDeferredOrder.STATUS_FAILED);
            loanDeferredOrderMapper.updateById(loanDeferredOrder);
            repaymentOrder.setActionType(BizConstants.LOAN_REPAYMENT_ORDER_TYPE_OPERAT_WALLET_FAILD);
            //执行冲账
            LoanOffset loanOffset = saveLoanOffset(repaymentOrder);
            //冲账
            loanInfoService.doLoanRepaymentGetInfo(loanOffset);
            doRepaymentLastService.updateWalletOrderToSuccess(repaymentOrder, true);
        }
        iRepaymentSmsService.smsSendDeferd(repaymentOrder, oldRepayDate);

    }

    @Override
    public boolean createRepaymentOrderAndPayTransForDeferNoSuccess(String walletNo, BigDecimal paystaskAmt, LoanIou loanIou, CustBankCard bankCard, LoanDeferredOrder loanDeferredOrder, ProductDeferredInfo productDeferredInfo) {
        log.info("主动还款延期包:生成还款订单-执行代扣操作:serialNo:{},bankCard:{}，loanDeferOrderNo：{}", loanIou.getLoanSerialNo(), bankCard.toString(), loanDeferredOrder.getLoanSerialDeferredNo());
        String custNo = bankCard.getCustNo();
        boolean result = false;
        //锁住客户账户再操作
        String lockKey = LoanConstants.CUST_ACCOUNT_LOCK_KEY_PREFIX + custNo;
        RLock lock = redisCache.lock(lockKey);
        try {
            long start = System.currentTimeMillis();
            result = lockedAndProssForDeferWalletNoSuccess(walletNo, paystaskAmt, loanIou.getLoanSerialNo(), bankCard, custNo, loanDeferredOrder);
            long end = System.currentTimeMillis();
            log.info("锁占用时间延期包，耗时：" + (end - start) + " ms");
        } catch (Exception e) {
            log.error("QucikRepay主动还款延期包", e);
            String className = this.getClass().getName();
            String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
            FeishuUtils.sendFeishuToMonit(className + "." + methodName, "QucikRepay主动还款-延期包", custNo, loanIou.getLoanSerialNo(), e);
        } finally {
            lock.unlock();
        }
        return result;
    }

    @Override
    public boolean createRepaymentOrderAndPayTransForNoSuccess(BigDecimal paystaskAmt, LoanIou loanIou, CustBankCard bankCard, String walletNo) {
        log.info("主动还款延期包:生成还款订单-执行代扣操作:serialNo:{},bankCard:{}", loanIou.getLoanSerialNo(), bankCard.toString());
        String custNo = bankCard.getCustNo();
        boolean result = false;
        //锁住客户账户再操作
        String lockKey = LoanConstants.CUST_ACCOUNT_LOCK_KEY_PREFIX + custNo;
        RLock lock = redisCache.lock(lockKey);
        try {
            long start = System.currentTimeMillis();
            result = lockedAndProssForWalletNoSuccess(paystaskAmt, loanIou.getLoanSerialNo(), bankCard, custNo, walletNo);
            long end = System.currentTimeMillis();
            log.info("锁占用时间延期包，耗时：" + (end - start) + " ms");
        } catch (Exception e) {
            log.error("QucikRepay主动还款延期包", e);
            String className = this.getClass().getName();
            String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
            FeishuUtils.sendFeishuToMonit(className + "." + methodName, "QucikRepay主动还款-延期包", custNo, loanIou.getLoanSerialNo(), e);
        } finally {
            lock.unlock();
        }
        return result;
    }

    @Override
    public boolean createRepaymentOrderForDeferBfWallet(LoanDeferredOrder loanDeferredOrder,
                                                        BigDecimal amtWallet, String walletNo, LoanIou loanIou) {
        //生成 re
        RepaymentOrder repaymentOrder = bLoanInfoService.createRepaymentOrderForDeferWalletNoSuccess(
                loanIou,
                BizConstants.LOAN_REPAYMENT_ORDER_TYPE_OPERATEDEFER_WALLET,
                "Active",
                loanDeferredOrder, amtWallet, walletNo);
        if (null != repaymentOrder) {
            return true;
        }
        return false;
    }

    @Override
    public RepaymentOrder createRepaymentOrderForfWalletNotAll(String actionType, BigDecimal amtWallet, String walletNo, LoanIou loanIou) {
        //生成 re
        RepaymentOrder repaymentOrder = bLoanInfoService.createRepaymentOrderForWalletNoSuccess(
                loanIou,
                actionType,
                "Active",
                amtWallet, walletNo);
        return repaymentOrder;
    }

    private LoanOffset saveLoanOffsetWalletAll(RepaymentOrder repaymentOrder) {
        LoanOffset loanOffset = new LoanOffset();
        loanOffset.setCustNo(repaymentOrder.getCustNo());
        loanOffset.setLoanSerialNo(repaymentOrder.getLoanSerialNo());
        loanOffset.setRepaymentNo(repaymentOrder.getRepaymentNo());
        loanOffset.setActionType(repaymentOrder.getActionType());
        loanOffset.setAmt(repaymentOrder.getRepaymentAmt());

        loanOffset.setPayTime(repaymentOrder.getPayTime());

        loanOffset.setLoanPrincipal(repaymentOrder.getLoanPrincipal());
        loanOffset.setRepaidPrincipal(repaymentOrder.getRepaidPrincipal());
        loanOffset.setServiceFee(repaymentOrder.getServiceFee());
        loanOffset.setRepaidServiceFee(repaymentOrder.getRepaidServiceFee());
        loanOffset.setLoanInterest(repaymentOrder.getLoanInterest());
        loanOffset.setRepaidInterest(repaymentOrder.getRepaidInterest());
        if (repaymentOrder.getLateFee() == null) {
            repaymentOrder.setLateFee(BigDecimal.ZERO);
        }
        if (repaymentOrder.getReduceFee() == null) {
            repaymentOrder.setReduceFee(BigDecimal.ZERO);
        }
        loanOffset.setLateFee(repaymentOrder.getLateFee());// 不需要 wqg沟通过 后期遇到延迟冲账的场景去回溯
        loanOffset.setRepaidLateFee(repaymentOrder.getRepaidLateFee());

        loanOffset.setLoanOffsetStatus(BizConstants.LOAN_OFFSET_STATUS_WAIT);
        loanOffset.setState(UserConstants.BUSINESS_NORMAL);
        loanOffsetService.insertLoanOffset(loanOffset);
        return loanOffset;
    }


    private LoanIouDeferred createLoanIouDeferred(LoanDeferredOrder loanDeferredOrder, LoanIou loanIou, RepaymentOrder repaymentOrder) {
        LoanIouDeferred loanIouDeferred = new LoanIouDeferred();
        loanIouDeferred.setCustNo(repaymentOrder.getCustNo());
        loanIouDeferred.setLoanSerialDeferredNo(IdWorker.getId());

        loanDeferredOrder.setLoanSerialDeferredNo(loanIouDeferred.getLoanSerialDeferredNo());

        loanIouDeferred.setLoanDeferOrderNo(loanDeferredOrder.getLoanDeferOrderNo());
        loanIouDeferred.setLoanSerialNo(repaymentOrder.getLoanSerialNo());
        loanIouDeferred.setProductDeferredId(loanDeferredOrder.getProductDeferredId());
        loanIouDeferred.setLoanDeferOrderNo(repaymentOrder.getLoanDeferOrderNo());
        loanIouDeferred.setInterestRate(loanDeferredOrder.getInterestRate());
        loanIouDeferred.setServiceRate(loanDeferredOrder.getServiceRate());
        // 计算新的到期日
        String nowRepayDate = loanIou.getRepayDate();
        if (null != loanIou.getIsDeferred() && loanIou.getIsDeferred() == 1) {
            nowRepayDate = loanIou.getDeferredRepayDate();
        }
        // 计算新的到期日
        loanIouDeferred.setRepayDate(DateUtils.getNewDay(nowRepayDate, loanDeferredOrder.getNumDeferredDay()));
        loanIouDeferred.setPeriodNum(loanDeferredOrder.getNumDeferredDay());
        BigDecimal serviceFee = loanIou.getLoanPrincipal().subtract(loanIou.getRepaidPrincipal()).multiply(loanDeferredOrder.getServiceRate());


        loanIouDeferred.setServiceFee(serviceFee);
        loanIouDeferred.setRepaidServiceFee(BigDecimal.ZERO);// 还了延期服务费
        BigDecimal interestFee = loanIou.getLoanPrincipal().subtract(loanIou.getRepaidPrincipal()).multiply(loanDeferredOrder.getInterestRate().multiply(new BigDecimal(loanDeferredOrder.getNumDeferredDay())));
        loanIouDeferred.setInterestFee(interestFee);
        loanIouDeferred.setRepaidInterestFee(BigDecimal.ZERO);// 还了延期利息
        loanIouDeferred.setStatus(9);
        loanIouDeferred.setState(BizConstants.BIZ_STATUS_1);
        loanIouDeferred.setContractNo(IdUtils.generateContractNo());
        loanIouDeferredMapper.insert(loanIouDeferred);
        return loanIouDeferred;
    }


    private LoanOffset saveLoanOffsetDeferWallet(RepaymentOrder repaymentOrder, LoanDeferredOrder loanDeferredOrder) {
        LoanOffset loanOffset = new LoanOffset();
        loanOffset.setCustNo(repaymentOrder.getCustNo());
        loanOffset.setLoanSerialNo(repaymentOrder.getLoanSerialNo());
        loanOffset.setRepaymentNo(repaymentOrder.getRepaymentNo());
        loanOffset.setActionType(repaymentOrder.getActionType());
        loanOffset.setAmt(repaymentOrder.getRepaymentAmt());

        loanOffset.setLoanSerialDeferredNo(loanDeferredOrder.getLoanSerialDeferredNo());

        loanOffset.setPayTime(repaymentOrder.getPayTime());

        loanOffset.setLoanPrincipal(repaymentOrder.getLoanPrincipal());
        loanOffset.setRepaidPrincipal(repaymentOrder.getRepaidPrincipal());
        loanOffset.setServiceFee(repaymentOrder.getServiceFee());
        loanOffset.setRepaidServiceFee(repaymentOrder.getRepaidServiceFee());
        loanOffset.setLoanInterest(repaymentOrder.getLoanInterest());
        loanOffset.setRepaidInterest(repaymentOrder.getRepaidInterest());
        if (repaymentOrder.getLateFee() == null) {
            repaymentOrder.setLateFee(BigDecimal.ZERO);
        }
        if (repaymentOrder.getReduceFee() == null) {
            repaymentOrder.setReduceFee(BigDecimal.ZERO);
        }
        loanOffset.setLateFee(repaymentOrder.getLateFee());// 不需要 wqg沟通过 后期遇到延迟冲账的场景去回溯
        loanOffset.setRepaidLateFee(repaymentOrder.getRepaidLateFee());

        loanOffset.setLoanOffsetStatus(BizConstants.LOAN_OFFSET_STATUS_WAIT);
        loanOffset.setState(UserConstants.BUSINESS_NORMAL);
        loanOffsetService.insertLoanOffset(loanOffset);
        return loanOffset;
    }


    /**
     * 部分钱包还款部分卡还款-<非>延期包
     *
     * @param serialNo
     * @param bankCard
     * @param custNo
     * @return
     */
    private boolean lockedAndProssForWalletNoSuccess(BigDecimal paystaskAmt, String serialNo, CustBankCard bankCard, String custNo, String walletNo) {
        LoanIou loanIou = getLoanIou(serialNo, custNo);
        CreditAccount creditAccount = creditAccountService.getNormalAcountOnLoan(custNo);
        if (null != loanIou && null != creditAccount) {
            // 创建订单
            RepaymentOrder repaymentOrder = bLoanInfoService.createRepaymentOrderForWalletPay(
                    paystaskAmt,
                    loanIou,
                    bankCard.getAuthorizationCode(),
                    BizConstants.LOAN_REPAYMENT_ORDER_TYPE_OPERAT_WALLET_PAYSTACK,
                    "Active");
            return goPayTransWithholdTransForWallet(bankCard, creditAccount, repaymentOrder, walletNo);
        }
        return false;
    }

    /**
     * 部分钱包还款部分卡还款-延期包
     *
     * @param serialNo
     * @param bankCard
     * @param custNo
     * @param loanDeferredOrder
     * @return
     */
    private boolean lockedAndProssForDeferWalletNoSuccess(String walletNo, BigDecimal paystaskAmt, String serialNo, CustBankCard bankCard, String custNo, LoanDeferredOrder loanDeferredOrder) {
        LoanIou loanIou = getLoanIou(serialNo, custNo);
        CreditAccount creditAccount = creditAccountService.getNormalAcountOnLoan(custNo);
        if (null != loanIou && null != creditAccount) {
            // 创建订单
            RepaymentOrder repaymentOrder = bLoanInfoService.createRepaymentOrderForDeferForminPay(
                    paystaskAmt,
                    loanIou,
                    bankCard.getAuthorizationCode(),
                    BizConstants.LOAN_REPAYMENT_ORDER_TYPE_OPERATEDEFER,
                    "Active",
                    loanDeferredOrder);
            return goPayTransWithholdTransForDeferWallet(walletNo, bankCard, creditAccount, repaymentOrder, loanDeferredOrder);
        }
        return false;
    }

    private boolean lockedAndProssForDefer(String serialNo, CustBankCard bankCard, String custNo, LoanDeferredOrder loanDeferredOrder) {
        LoanIou loanIou = getLoanIou(serialNo, custNo);
        CreditAccount creditAccount = creditAccountService.getNormalAcountOnLoan(custNo);
        if (null != loanIou && null != creditAccount) {
            // 创建订单
            RepaymentOrder repaymentOrder = bLoanInfoService.createRepaymentOrderForDefer(
                    loanIou,
                    bankCard.getAuthorizationCode(),
                    BizConstants.LOAN_REPAYMENT_ORDER_TYPE_OPERATEDEFER,
                    "Active",
                    loanDeferredOrder);
            return goPayTransWithholdTransForDefer(bankCard, creditAccount, repaymentOrder, loanDeferredOrder);
        }
        return false;
    }

    /**
     * 延期金融包的代扣-无钱包
     *
     * @param bankCard
     * @param creditAccount
     * @param repaymentOrder
     * @return
     */
    private boolean goPayTransWithholdTransForDefer(CustBankCard bankCard, CreditAccount creditAccount, RepaymentOrder repaymentOrder, LoanDeferredOrder loanDeferredOrder) {
        boolean result = false;
        if (null != repaymentOrder) {
            //发起代扣
            //设置代扣流水号+标示
            repaymentOrder.setPayTransSerialNo(IdUtils.reqId() + BizConstants.PAY_TRANS_FLAG_DF);
            Map<String, Boolean> res = bLoanInfoService.payTransWithholdTrans(repaymentOrder, bankCard.getEmail());
            if (!res.get("isFail")) {
                // pending和success都要返回客户端成功
                result = true;
                if (res.get("resStatus")) {
                    // 推送MQ
                    repaymentMqService.selfdeferRepaymentMq(repaymentOrder, creditAccount);
                }
            } else {
                log.info("主动还款：{},代扣失败", repaymentOrder.getCustNo());
            }
        } else {
            log.info("主动还款：{},订单创建失败", repaymentOrder.getCustNo());
        }
        return result;
    }

    /**
     * <非>延期金融包的代扣-含有部分钱包
     *
     * @param bankCard
     * @param creditAccount
     * @param repaymentOrder
     * @return
     */
    private boolean goPayTransWithholdTransForWallet(CustBankCard bankCard, CreditAccount creditAccount, RepaymentOrder repaymentOrder, String walletNo) {
        boolean result = false;
        if (null != repaymentOrder) {
            //发起代扣
            //设置代扣流水号+标示
            repaymentOrder.setPayTransSerialNo(walletNo + BizConstants.PAY_TRANS_FLAG_PAY_ALL_WALLET);
            Map<String, Boolean> res = bLoanInfoService.payTransWithholdTrans(repaymentOrder, bankCard.getEmail());
            if (!res.get("isFail")) {
                // pending和success都要返回客户端成功
                result = true;
                if (res.get("resStatus")) {
                    //推送MQ
                    repaymentMqService.selfWalletForBfenRepaymentMq(repaymentOrder, creditAccount.getId());
                }


            } else {
                log.info("主动还款：{},代扣失败", repaymentOrder.getCustNo());
            }
        } else {
            log.info("主动还款：{},订单创建失败", repaymentOrder.getCustNo());
        }
//        if (!result) { repayAll 不需要解冻
//            doRepaymentLastService.updateWalletOrderToFailed(walletNo);
//        }
        return result;
    }

    /**
     * 延期金融包的代扣-含有部分钱包
     *
     * @param bankCard
     * @param creditAccount
     * @param repaymentOrder
     * @return
     */
    private boolean goPayTransWithholdTransForDeferWallet(String walletNo, CustBankCard bankCard, CreditAccount creditAccount, RepaymentOrder repaymentOrder, LoanDeferredOrder loanDeferredOrder) {
        boolean result = false;
        if (null != repaymentOrder) {
            //发起代扣
            //设置代扣流水号+标示
            repaymentOrder.setPayTransSerialNo(IdUtils.reqId() + BizConstants.PAY_TRANS_FLAG_DF_WALLET);
            Map<String, Boolean> res = bLoanInfoService.payTransWithholdTrans(repaymentOrder, bankCard.getEmail());
            if (!res.get("isFail")) {
                result = true;
                if (res.get("resStatus")) {
                    // 推送MQ
                    repaymentMqService.selfdeferWalletForBfenRepaymentMq(repaymentOrder, creditAccount);
                }

            } else {
                log.info("主动还款：{},代扣失败", repaymentOrder.getCustNo());
            }
        } else {
            log.info("主动还款：{},订单创建失败", repaymentOrder.getCustNo());
        }
        if (!result) {
            loanDeferredOrder.setStatus(LoanDeferredOrder.STATUS_FAILED);
            loanDeferredOrderMapper.updateById(loanDeferredOrder);
            repaymentOrderMapper.updateRepayStatusToFaildByPayTransSerialNo(walletNo);
            doRepaymentLastService.updateWalletOrderToFailed(loanDeferredOrder.getWalletNo(), true);
        }
        return result;
    }

    /**
     * @param dataJson
     * @return
     */
    @Override
    public JSONObject creatPayOrder(JSONObject dataJson) {
        String serialNo = dataJson.get("loanSerialNo").toString();
        boolean useWallet = dataJson.getBoolean("useWallet");
        Integer deferredId = dataJson.getInteger("deferredId");
        LoanIou loanIou = loanIouService.getLoanIouByLoanSerialNo(serialNo);
        if (null == deferredId) {
            //非延期
            return delRepayAll(useWallet, loanIou);
        }
        // 直接生成连接 iou计算的钱
        return delDefferRepay(useWallet, loanIou, deferredId);
    }

    /**
     * @param useWallet
     * @param loanIou
     * @return
     */
    private JSONObject delDefferRepay(boolean useWallet, LoanIou loanIou, int deferredId) {
        ProductDeferredInfo productDeferredInfo = productDeferredInfoMapper.selectById(deferredId);
        BigDecimal minPay = processForIouDefferredService.getMinPay(loanIou, productDeferredInfo);
        if (useWallet) {
            return delDefferRepayUseWallet(loanIou, minPay, deferredId);
        }
        LoanDeferredOrder loanDeferredOrder = createLoanDeferredOrder(loanIou.getLoanSerialNo(), deferredId, null, null);
        // 延期还款
        return goPayStack(loanIou, minPay, BizConstants.PAY_TRANS_FLAG_DF, BizConstants.LOAN_REPAYMENT_ORDER_TYPE_OPERATEDEFER_CARD_STACk, "", loanDeferredOrder);
    }

    /**
     * 使用钱包支付延期-新卡
     *
     * @param loanIou
     * @param minPay
     * @return
     */
    private JSONObject delDefferRepayUseWallet(LoanIou loanIou, BigDecimal minPay, int deferredId) {
        //创建 loan_deferred_order 状态状态9申请中
        JSONObject amtWalletObj = doRepaymentLastService.getAmtWallet(minPay, loanIou.getCustNo(), loanIou.getLoanSerialNo(), true);
        BigDecimal amtWallet = amtWalletObj.getBigDecimal("amtWallet");
        String walletNo = amtWalletObj.getString("walletOrderNo");
        LoanDeferredOrder loanDeferredOrder = createLoanDeferredOrder(loanIou.getLoanSerialNo(), deferredId, amtWallet, walletNo);
        if (null == loanDeferredOrder) {
            doRepaymentLastService.updateWalletOrderToFailed(walletNo, true);
            throw new BusinessException(RspEnmu.EXTERNAL_API_RSP_NULL);
        }
        if (amtWallet.compareTo(BigDecimal.ZERO) <= 0) {
            log.info("新卡延期+钱包：钱包余额小于等于0,改为卡全款-------");
            return goPayStack(loanIou, minPay, BizConstants.PAY_TRANS_FLAG_DF, BizConstants.LOAN_REPAYMENT_ORDER_TYPE_OPERATEDEFER_CARD_STACk, "", loanDeferredOrder);
        }
        if (amtWallet.compareTo(minPay) == 0) {
            // 钱包余额
            log.info("新卡延期+钱包：钱包余额够支付费用,,{},{}", amtWallet, minPay);
            return goDeferdByWalletEnough(loanIou, amtWallet, walletNo, deferredId, loanDeferredOrder);
        }
        log.info("新卡延期+钱包：钱包余额小于等于于需要支付的费用，扣掉返回钱包余额,{},{}", amtWallet, minPay);

        boolean isOk = createRepaymentOrderForDeferBfWallet(loanDeferredOrder, amtWallet, walletNo, loanIou);
        if (!isOk) {
            doRepaymentLastService.updateWalletOrderToFailed(walletNo, true);
            throw new BusinessException(RspEnmu.EXTERNAL_API_RSP_NULL);
        }
        // 卡支付的钱
        BigDecimal paystaskAmt = minPay.subtract(amtWallet);
        // 不够支付，生成部分还款
        return goPayStack(loanIou, paystaskAmt, BizConstants.PAY_TRANS_FLAG_DF_WALLET, BizConstants.LOAN_REPAYMENT_ORDER_TYPE_OPERATEDEFER_CARD_STACk, walletNo, loanDeferredOrder);
    }

    private LoanDeferredOrder createLoanDeferredOrder(String serialNo, int deferredId, BigDecimal amtWallet, String walletNo) {
        LoanIou loanIou = loanIouService.getLoanIouByLoanSerialNo(serialNo);
        ProductInfo productInfo = processForIouDefferredService.getProductId(loanIou);
        ProductDeferredInfo productDeferredInfo = productDeferredInfoMapper.selectById(deferredId);

        BigDecimal leftAmt = loanIou.getLoanAmt().subtract(loanIou.getRepaidPrincipal());

        LoanDeferredOrder loanDeferredOrder = new LoanDeferredOrder();

        loanDeferredOrder.setLoanDeferOrderNo(IdWorker.getId());
        loanDeferredOrder.setCustNo(loanIou.getCustNo());

        loanDeferredOrder.setLoanSerialNo(serialNo);
        loanDeferredOrder.setProductId(productInfo.getId());
        loanDeferredOrder.setProductCode(productInfo.getProductCode());
        loanDeferredOrder.setProductDeferredId(deferredId);
        loanDeferredOrder.setCreditRating(productInfo.getCreditRating());
        loanDeferredOrder.setWalletNo(walletNo);//repayorder transF需要

        loanDeferredOrder.setInterestRate(productDeferredInfo.getInterestRate());
        loanDeferredOrder.setServiceRate(productDeferredInfo.getServiceRate());

        loanDeferredOrder.setNumDeferredDay(productDeferredInfo.getNumDeferredDay());
        loanDeferredOrder.setNumDeferredTimes(productDeferredInfo.getNumDeferredTimes());
        loanDeferredOrder.setNumDeferredRetainDay(productDeferredInfo.getNumDeferredRetainDay());
        loanDeferredOrder.setMinRepayPrincipal(productDeferredInfo.getMinRepayPrincipal());
        loanDeferredOrder.setMaxRepayPrincipal(productDeferredInfo.getMaxRepayPrincipal());
        loanDeferredOrder.setExpireTime(productDeferredInfo.getExpireTime());
        loanDeferredOrder.setShowIsActive(productDeferredInfo.getShowIsActive());
        loanDeferredOrder.setDeferredServiceFee(leftAmt.multiply(productDeferredInfo.getServiceRate()));
        loanDeferredOrder.setDeferredInterestFee(leftAmt.multiply(productDeferredInfo.getInterestRate().multiply(new BigDecimal(productDeferredInfo.getNumDeferredDay()))));

        loanDeferredOrder.setLoanPrincipal(loanIou.getLoanPrincipal());
        loanDeferredOrder.setRepaidPrincipal(loanIou.getRepaidPrincipal());
        loanDeferredOrder.setServiceFee(loanIou.getServiceFee());
        loanDeferredOrder.setRepaidServiceFee(loanIou.getRepaidServiceFee());
        loanDeferredOrder.setLoanInterest(loanIou.getLoanInterest());
        loanDeferredOrder.setRepaidInterest(loanIou.getRepaidInterest());
        loanDeferredOrder.setLateFee(loanIou.getRepaidLateFee());

        loanDeferredOrder.setStatus(LoanDeferredOrder.STATUS_WAIT);
        loanDeferredOrder.setCreateBy("system");

        loanDeferredOrder.setRepayAmt(processForIouDefferredService.getMinPay(loanIou, productDeferredInfo));
        int numInsert = loanDeferredOrderMapper.insert(loanDeferredOrder);
        if (numInsert == 1) {
            return loanDeferredOrder;
        } else {
            return null;
        }
    }

    /**
     * 钱包全额支付
     *
     * @param loanIou
     * @param amtWallet
     * @param walletNo
     * @return
     */
    private JSONObject goDeferdByWalletEnough(LoanIou loanIou, BigDecimal amtWallet, String walletNo, int deferredId, LoanDeferredOrder loanDeferredOrder) {
        ProductDeferredInfo productDeferredInfo = productDeferredInfoMapper.selectById(deferredId);
        JSONObject rst = new JSONObject();
        RepaymentOrder repaymentOrder = bLoanInfoService.createRepaymentOrderForDeferWalletSuccess(
                loanIou,
                BizConstants.LOAN_REPAYMENT_ORDER_TYPE_OPERATEDEFER_WALLET,
                "Active",
                loanDeferredOrder, amtWallet, walletNo);
        if (null != repaymentOrder) {
            SendResult sendResult = repaymentMqService.selfdeferWalletForAllPayRepaymentMq(loanIou, productDeferredInfo, repaymentOrder, amtWallet, walletNo);
            if (sendResult.getSendStatus().equals(SendStatus.SEND_OK)) {
                rst.put("isWalletPayAll", true);
            } else {
                doRepaymentLastService.updateWalletOrderToFailed(walletNo, true);
                throw new BusinessException(RspEnmu.EXTERNAL_API_RSP_NULL);
            }
        } else {
            log.info("钱包全额支付延期还款，创建订单失败");
            doRepaymentLastService.updateWalletOrderToFailed(walletNo, true);
            throw new BusinessException(RspEnmu.EXTERNAL_API_RSP_NULL);
        }

        return rst;
    }

    /**
     * 非延期-无无卡支付
     *
     * @param useWallet
     * @param loanIou
     * @return
     */
    private JSONObject delRepayAll(boolean useWallet, LoanIou loanIou) {
        BigDecimal minPay = LoanIou.calculationOverdueAmount(loanIou);
        if (useWallet) {
            return delRepayAllUseWallet(loanIou, minPay);
        }
        return goPayStack(loanIou, minPay, "", BizConstants.LOAN_REPAYMENT_ORDER_TYPE_OPERAT_CARD_STACK, "", null);
    }

    private JSONObject delRepayAllUseWallet(LoanIou loanIou, BigDecimal minPay) {

        // 得到选择的延期产品需要支付的金额，远程获取钱包，钱包不够，就返回钱包最小的金额
        JSONObject amtWalletObj = doRepaymentLastService.getAmtWallet(minPay, loanIou.getCustNo(), loanIou.getLoanSerialNo(), false);
        BigDecimal amtWallet = amtWalletObj.getBigDecimal("amtWallet");
        String walletNo = amtWalletObj.getString("walletOrderNo");
        if (amtWallet.compareTo(BigDecimal.ZERO) <= 0) {
            log.info("钱包余额小于等于0,改为卡全款-------");
            // 卡全款不需要设置标示
            return goPayStack(loanIou, minPay, "", BizConstants.LOAN_REPAYMENT_ORDER_TYPE_OPERATE, "", null);
        }
        if (amtWallet.compareTo(minPay) == 0) {
            // 钱包余额
            log.info("钱包余额够支付费用,,{},{}", amtWallet, minPay);
            return goRepayAllByWallet(loanIou, amtWallet, walletNo);
        }
        log.info("钱包余额小于等于于需要支付的费用，扣掉返回钱包余额,{},{}", amtWallet, minPay);
        // 部分钱包直接扣款
            // 钱包支付全额还款，不需要等待卡支付回调进行冲账，06-15有沟通
            try {
                RepaymentOrder repaymentOrderWallet = createRepaymentOrderForfWalletNotAll(BizConstants.LOAN_REPAYMENT_ORDER_TYPE_OPERAT_WALLET, amtWallet, walletNo, loanIou);
                if (null != repaymentOrderWallet) {
                    SendResult sendResult = repaymentMqService.selfWalletForAllPayRepaymentMq(loanIou, repaymentOrderWallet);
                    if (!sendResult.getSendStatus().equals(SendStatus.SEND_OK)) {
                        doRepaymentLastService.updateWalletOrderToFailed(walletNo, false);
                    }
                } else {
                    log.info("使用钱包，全额还款失败；repaymentOrder创建失败");
                    // 解冻钱包
                    doRepaymentLastService.updateWalletOrderToFailed(walletNo, false);
                    throw new BusinessException(RspEnmu.NETWORK_BUSY);
                }
            } catch (Exception e) {
                doRepaymentLastService.updateWalletOrderToFailed(walletNo, false);
                throw new RuntimeException(e);
            }

        minPay = minPay.subtract(amtWallet);
        // 不够支付，生成部分还款
        return goPayStack(loanIou, minPay, "", BizConstants.LOAN_REPAYMENT_ORDER_TYPE_OPERATE, "", null);
    }

    private JSONObject goRepayAllByWallet(LoanIou loanIou, BigDecimal amtWallet, String walletNo) {
        JSONObject rst = new JSONObject();
        // 创建repayMentOrder
        RepaymentOrder repaymentOrder = bLoanInfoService.createRepaymentOrderRepayAllWalletNoSuccess(
                loanIou,
                BizConstants.LOAN_REPAYMENT_ORDER_TYPE_OPERAT_WALLET,
                "Active", amtWallet, walletNo);
        if (null != repaymentOrder) {
            try {
                SendResult sendResult = repaymentMqService.selfWalletForAllPayRepaymentMq(loanIou, repaymentOrder);
                if (sendResult.getSendStatus().equals(SendStatus.SEND_OK)) {
                    rst.put("isWalletPayAll", true);
                } else {
                    log.info("钱包全额支付还款，发送mq失败：{}", sendResult);
                    doRepaymentLastService.updateWalletOrderToFailed(walletNo, false);
                    throw new BusinessException(RspEnmu.EXTERNAL_API_RSP_NULL);
                }
            } catch (BusinessException e) {
                doRepaymentLastService.updateWalletOrderToFailed(walletNo, false);
                throw new RuntimeException(e);
            }
        } else {
            log.info("使用钱包，全额还款失败；repaymentOrder创建失败");
            // 解冻钱包
            doRepaymentLastService.updateWalletOrderToFailed(walletNo, false);
            throw new BusinessException(RspEnmu.EXTERNAL_API_RSP_NULL);
        }
        return rst;
    }

    private JSONObject goPayStack(LoanIou loanIou, BigDecimal amt, String payFlag, String actionType, String walletNo, LoanDeferredOrder loanDeferredOrder) {
        log.info("goPayStack:{},{},{},{},{},{}", loanIou.toString(), amt, payFlag, actionType, walletNo, loanDeferredOrder == null ? "" : loanDeferredOrder.toString());
        String userId = getUserId();
        String userEmail = userId.substring(userId.length() - 10) + EMAIL;
        String payTransSerialNo = IdUtils.reqId() + payFlag;
        if (StringUtils.isNotEmpty(walletNo)) {
            // 存在钱包还款，延期下 ，paystack需要replace payFlag获取钱包订单进行操作
            payTransSerialNo = walletNo + payFlag;
        }

        RepaymentOrder repaymentOrder = bLoanInfoService.createRepaymentOrderForPayNewCard(loanIou, actionType, "Active", payTransSerialNo, amt, loanDeferredOrder);

        JSONObject reqParam = new JSONObject();
        reqParam.put("email", userEmail);
        reqParam.put("amount", repaymentOrder.getRepaymentAmt().multiply(new BigDecimal("100")));
        reqParam.put("reference", payTransSerialNo);
//        reqParam.put("callback_url", "http://jamnsinx.antiantech.com/callback/bind/res");
        // {"status":true,"message":"Authorization URL created","data":{"authorization_url":"https://checkout.paystack.com/0peioxfhpn","access_code":"0peioxfhpn","reference":"7PVGX8MEk85tgeEpVDtD"}}
        JSONObject apiRes = null;
        try {
            apiRes = externalApiService.invokePayStackApi("Paystack-CardPay-Initialize-Transaction", payStackConfig.getInitializeTransaction(), "POST", reqParam, null);
        } catch (BusinessException e) {
            log.error("新卡还款：错误repaymentOrder:{}", repaymentOrder.getRepaymentNo(), e);
            if (StringUtils.isNotEmpty(walletNo)) {
                // 解冻钱包
                doRepaymentLastService.updateWalletOrderToFailed(walletNo, false);
                repaymentOrderMapper.updateRepayStatusToFaildByPayTransSerialNo(walletNo);
            }
            repaymentOrder.setRepayStatus(BizConstants.REPAYMENT_ORDER_STATUS_FAIL);
            repaymentOrder.setRemark(repaymentOrder.getRemark() + "::" + e.getDetails());
            repaymentOrderService.updateRepaymentOrder(repaymentOrder);
            if (null != loanDeferredOrder) {
                loanDeferredOrder.setStatus(LoanDeferredOrder.STATUS_FAILED);
                loanDeferredOrderMapper.updateById(loanDeferredOrder);
            }
            throw e;
        }
        JSONObject rst = new JSONObject();
        rst.put("authorizationUrl", apiRes.getString("authorization_url"));
        rst.put("bindSerialNo", payTransSerialNo);
        rst.put("isWalletPayAll", false);
        return rst;
    }


//    private void doLoanOffset(LoanOffset loanOffset) {
//        //锁住客户账户再操作
//        String lockKey = BizConstants.CUST_ACCOUNT_LOCK_KEY_PREFIX + loanOffset.getCustNo();
//
//        int j = 0;//重试次数
//        while (j < BizConstants.CUST_ACCOUNT_LOCK_REGET_COUNT) {//重试次数内
//            j++;
//            log.info("Repayment 客户号 {} 第 {} 次获取账户锁", loanOffset.getCustNo(), j);
//            boolean lock = redisCache.lock(lockKey);//获取锁
//
//            if (lock) {
//                try {
//                    //执行冲账
//                    loanInfoService.doLoanRepaymentGetInfo(loanOffset);
//                    //无需重试
//                    break;
//                } finally {
//                    //释放锁
//                    redisCache.unLock(lockKey);
//                }
//            } else {
//                log.info("Repayment 客户号 {} 第 {} 次获取账户锁失败", loanOffset.getCustNo(), j);
//
//                try {
//                    Thread.sleep(BizConstants.CUST_ACCOUNT_LOCK_SLEEP_TIME);
//                } catch (InterruptedException e) {
//                    log.error("Repayment 线程 sleep 异常", e);
//                }
//            }
//        }
//    }

}
